"""
AI Agent Pro - 工具管理器
"""

import asyncio
import importlib
import inspect
import pkgutil
from typing import Any, Dict, List, Optional, Type, Union

from app.core.exceptions import ToolError
from app.core.logging import get_logger
from app.tools.base import BaseTool, ToolResult, ToolSchema, ToolType

logger = get_logger(__name__)


class ToolManager:
    """工具管理器"""
    
    def __init__(self):
        self._tools: Dict[str, BaseTool] = {}
        self._tool_classes: Dict[str, Type[BaseTool]] = {}
        self._categories: Dict[ToolType, List[str]] = {}
        
        # 初始化分类
        for tool_type in ToolType:
            self._categories[tool_type] = []
    
    def register_tool(self, tool: Union[BaseTool, Type[BaseTool]], **kwargs) -> str:
        """
        注册工具
        
        Args:
            tool: 工具实例或工具类
            **kwargs: 工具初始化参数
            
        Returns:
            工具名称
            
        Raises:
            ToolError: 工具注册失败
        """
        try:
            # 如果是类，实例化
            if inspect.isclass(tool) and issubclass(tool, BaseTool):
                tool_instance = tool(**kwargs)
            elif isinstance(tool, BaseTool):
                tool_instance = tool
            else:
                raise ToolError("unknown", "无效的工具类型")
            
            tool_name = tool_instance.schema.name
            
            # 检查是否已存在
            if tool_name in self._tools:
                logger.warning(f"工具 {tool_name} 已存在，将被覆盖")
            
            # 注册工具
            self._tools[tool_name] = tool_instance
            self._tool_classes[tool_name] = tool_instance.__class__
            
            # 添加到分类
            tool_type = tool_instance.schema.tool_type
            if tool_name not in self._categories[tool_type]:
                self._categories[tool_type].append(tool_name)
            
            logger.info(f"工具注册成功: {tool_name} ({tool_type.value})")
            return tool_name
            
        except Exception as e:
            logger.error(f"工具注册失败: {str(e)}")
            raise ToolError("registration", f"工具注册失败: {str(e)}")
    
    def unregister_tool(self, tool_name: str) -> bool:
        """
        注销工具
        
        Args:
            tool_name: 工具名称
            
        Returns:
            是否成功注销
        """
        if tool_name not in self._tools:
            logger.warning(f"工具 {tool_name} 不存在")
            return False
        
        tool = self._tools[tool_name]
        tool_type = tool.schema.tool_type
        
        # 从注册表中移除
        del self._tools[tool_name]
        del self._tool_classes[tool_name]
        
        # 从分类中移除
        if tool_name in self._categories[tool_type]:
            self._categories[tool_type].remove(tool_name)
        
        logger.info(f"工具注销成功: {tool_name}")
        return True
    
    def get_tool(self, tool_name: str) -> Optional[BaseTool]:
        """
        获取工具实例
        
        Args:
            tool_name: 工具名称
            
        Returns:
            工具实例
        """
        return self._tools.get(tool_name)
    
    def has_tool(self, tool_name: str) -> bool:
        """
        检查工具是否存在
        
        Args:
            tool_name: 工具名称
            
        Returns:
            是否存在
        """
        return tool_name in self._tools
    
    def list_tools(
        self,
        tool_type: Optional[ToolType] = None,
        enabled_only: bool = False
    ) -> List[str]:
        """
        列出工具名称
        
        Args:
            tool_type: 工具类型过滤
            enabled_only: 只返回启用的工具
            
        Returns:
            工具名称列表
        """
        tools = []
        
        if tool_type:
            candidate_tools = self._categories.get(tool_type, [])
        else:
            candidate_tools = list(self._tools.keys())
        
        for tool_name in candidate_tools:
            tool = self._tools.get(tool_name)
            if tool and (not enabled_only or tool.schema.enabled):
                tools.append(tool_name)
        
        return tools
    
    def get_tool_schemas(
        self,
        tool_type: Optional[ToolType] = None,
        enabled_only: bool = False
    ) -> List[ToolSchema]:
        """
        获取工具模式列表
        
        Args:
            tool_type: 工具类型过滤
            enabled_only: 只返回启用的工具
            
        Returns:
            工具模式列表
        """
        schemas = []
        
        for tool_name in self.list_tools(tool_type, enabled_only):
            tool = self._tools.get(tool_name)
            if tool:
                schemas.append(tool.schema)
        
        return schemas
    
    def get_openai_functions(
        self,
        tool_names: Optional[List[str]] = None,
        tool_type: Optional[ToolType] = None
    ) -> List[Dict[str, Any]]:
        """
        获取OpenAI函数调用格式的工具定义
        
        Args:
            tool_names: 指定工具名称列表
            tool_type: 工具类型过滤
            
        Returns:
            OpenAI函数格式的工具定义列表
        """
        functions = []
        
        if tool_names:
            target_tools = [name for name in tool_names if name in self._tools]
        else:
            target_tools = self.list_tools(tool_type, enabled_only=True)
        
        for tool_name in target_tools:
            tool = self._tools.get(tool_name)
            if tool and tool.schema.enabled:
                functions.append(tool.schema.to_openai_format())
        
        return functions
    
    async def execute_tool(
        self,
        tool_name: str,
        **kwargs
    ) -> ToolResult:
        """
        执行工具
        
        Args:
            tool_name: 工具名称
            **kwargs: 工具参数
            
        Returns:
            执行结果
            
        Raises:
            ToolError: 工具不存在或执行失败
        """
        if tool_name not in self._tools:
            raise ToolError(tool_name, "工具不存在")
        
        tool = self._tools[tool_name]
        
        if not tool.schema.enabled:
            raise ToolError(tool_name, "工具已禁用")
        
        return await tool.execute(**kwargs)
    
    async def execute_tools_parallel(
        self,
        tool_calls: List[Dict[str, Any]]
    ) -> List[ToolResult]:
        """
        并行执行多个工具
        
        Args:
            tool_calls: 工具调用列表，格式: [{"name": "tool_name", "params": {...}}, ...]
            
        Returns:
            执行结果列表
        """
        tasks = []
        
        for call in tool_calls:
            tool_name = call.get("name")
            params = call.get("params", {})
            
            if tool_name in self._tools:
                task = self.execute_tool(tool_name, **params)
                tasks.append(task)
            else:
                # 创建失败结果
                result = ToolResult(
                    success=False,
                    error=f"工具 {tool_name} 不存在"
                )
                tasks.append(asyncio.create_task(asyncio.coroutine(lambda: result)()))
        
        # 并行执行
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 处理异常
        processed_results = []
        for result in results:
            if isinstance(result, Exception):
                processed_results.append(ToolResult(
                    success=False,
                    error=str(result)
                ))
            else:
                processed_results.append(result)
        
        return processed_results
    
    def search_tools(
        self,
        query: str,
        tool_type: Optional[ToolType] = None
    ) -> List[str]:
        """
        搜索工具
        
        Args:
            query: 搜索关键词
            tool_type: 工具类型过滤
            
        Returns:
            匹配的工具名称列表
        """
        query_lower = query.lower()
        matched_tools = []
        
        for tool_name in self.list_tools(tool_type):
            tool = self._tools.get(tool_name)
            if not tool:
                continue
            
            # 搜索工具名称、描述和标签
            schema = tool.schema
            search_text = f"{schema.name} {schema.description} {' '.join(schema.tags)}".lower()
            
            if query_lower in search_text:
                matched_tools.append(tool_name)
        
        return matched_tools
    
    def get_tool_statistics(self) -> Dict[str, Any]:
        """
        获取工具统计信息
        
        Returns:
            统计信息
        """
        total_tools = len(self._tools)
        enabled_tools = len([t for t in self._tools.values() if t.schema.enabled])
        
        # 按类型统计
        type_stats = {}
        for tool_type, tool_names in self._categories.items():
            type_stats[tool_type.value] = len(tool_names)
        
        # 执行统计
        total_executions = sum(tool.execution_count for tool in self._tools.values())
        total_execution_time = sum(tool.total_execution_time for tool in self._tools.values())
        
        return {
            "total_tools": total_tools,
            "enabled_tools": enabled_tools,
            "disabled_tools": total_tools - enabled_tools,
            "type_distribution": type_stats,
            "total_executions": total_executions,
            "total_execution_time": total_execution_time,
            "average_execution_time": (
                total_execution_time / total_executions
                if total_executions > 0 else 0.0
            )
        }
    
    def enable_tool(self, tool_name: str) -> bool:
        """
        启用工具
        
        Args:
            tool_name: 工具名称
            
        Returns:
            是否成功
        """
        if tool_name not in self._tools:
            return False
        
        self._tools[tool_name].enable()
        return True
    
    def disable_tool(self, tool_name: str) -> bool:
        """
        禁用工具
        
        Args:
            tool_name: 工具名称
            
        Returns:
            是否成功
        """
        if tool_name not in self._tools:
            return False
        
        self._tools[tool_name].disable()
        return True
    
    def auto_discover_tools(self, package_name: str = "app.tools.builtin"):
        """
        自动发现并注册工具
        
        Args:
            package_name: 包名
        """
        try:
            # 导入包
            package = importlib.import_module(package_name)
            
            # 遍历包中的模块
            for _, module_name, _ in pkgutil.iter_modules(package.__path__):
                try:
                    full_module_name = f"{package_name}.{module_name}"
                    module = importlib.import_module(full_module_name)
                    
                    # 查找工具类
                    for name, obj in inspect.getmembers(module):
                        if (inspect.isclass(obj) and
                            issubclass(obj, BaseTool) and
                            obj != BaseTool):
                            
                            try:
                                self.register_tool(obj)
                            except Exception as e:
                                logger.warning(f"注册工具 {name} 失败: {str(e)}")
                
                except Exception as e:
                    logger.warning(f"导入模块 {module_name} 失败: {str(e)}")
        
        except Exception as e:
            logger.error(f"自动发现工具失败: {str(e)}")
    
    def export_tool_config(self, tool_name: str) -> Optional[Dict[str, Any]]:
        """
        导出工具配置
        
        Args:
            tool_name: 工具名称
            
        Returns:
            工具配置
        """
        if tool_name not in self._tools:
            return None
        
        tool = self._tools[tool_name]
        
        return {
            "name": tool.schema.name,
            "description": tool.schema.description,
            "type": tool.schema.tool_type.value,
            "version": tool.schema.version,
            "parameters": [param.dict() for param in tool.schema.parameters],
            "examples": tool.schema.examples,
            "tags": tool.schema.tags,
            "enabled": tool.schema.enabled,
            "timeout": tool.schema.timeout,
            "config": tool.config
        }
    
    def import_tool_config(self, config: Dict[str, Any]) -> bool:
        """
        导入工具配置
        
        Args:
            config: 工具配置
            
        Returns:
            是否成功
        """
        # 这里需要根据配置重新创建工具实例
        # 实际实现需要更复杂的逻辑
        logger.info(f"导入工具配置: {config.get('name', 'unknown')}")
        return True


# 全局工具管理器实例
tool_manager = ToolManager()


# 工具注册装饰器
def register_tool(manager: ToolManager = None):
    """工具注册装饰器"""
    def decorator(tool_class):
        target_manager = manager or tool_manager
        target_manager.register_tool(tool_class)
        return tool_class
    
    return decorator


# 导出
__all__ = [
    "ToolManager",
    "tool_manager",
    "register_tool",
]